package jxtend.processor.eclipse.visitor;

import java.lang.reflect.Constructor;
import java.util.List;

import jxtend.processor.eclipse.visitor.handler.ASTNodeVisitorContext;
import jxtend.processor.reflect.ReflectField;
import jxtend.processor.utils.ReflectUtils;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;

@SuppressWarnings("restriction")
public class UndoAnnotationResolveASTNodeVisitor implements ASTNodeVisitor {

	private static final Constructor<AnnotationBinding> annotationBindingConstructor =
			ReflectUtils.getInaccessibleConstructor(AnnotationBinding.class, Annotation.class);

	private UndoAnnotationResolveASTNodeVisitor() {
		// Do nothing
	}

	public static ASTVisitor createASTVisitor(List<ASTNode> parentNodes) {
		return ASTVisitorFactory.create(new UndoAnnotationResolveASTNodeVisitor(), parentNodes);
	}

	private static final ReflectField<Annotation, AnnotationBinding> compilerAnnotationOfAnnotation =
		ReflectField.getField(Annotation.class, AnnotationBinding.class, "compilerAnnotation");
	
	@Override
	public boolean visit(ASTNodeVisitorContext context, ASTNode node, Scope scope) {
		
		if (node instanceof Annotation) {
//			AnnotationBinding compilerAnnotation = null;
//			if (((Annotation) node).resolvedType != null) {
//				compilerAnnotation = ReflectUtils.newInstance(annotationBindingConstructor, node);
//			}
//
//			compilerAnnotationOfAnnotation.set((Annotation) node, compilerAnnotation);

//			((Annotation) node).recipient = null;
//			((Annotation) node).resolvedType = null;
		} else if (node instanceof AbstractMethodDeclaration) {
			AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) node;

			if (abstractMethodDeclaration.binding != null) {
				abstractMethodDeclaration.binding.tagBits &= ~TagBits.AnnotationResolved;
			}
		} else if (node instanceof Argument) {
			Argument argument = (Argument) node;

			if (argument.binding != null) {
				argument.binding.tagBits &= ~TagBits.AnnotationResolved;
			}
		} else if (node instanceof FieldDeclaration) {
			FieldDeclaration fieldDeclaration = (FieldDeclaration) node;

			if (fieldDeclaration.binding != null) {
				fieldDeclaration.binding.tagBits &= ~TagBits.AnnotationResolved;
			}
		} else if (node instanceof LocalDeclaration) {
			LocalDeclaration localDeclaration = (LocalDeclaration) node;

			if (localDeclaration.binding != null) {
				localDeclaration.binding.tagBits &= ~TagBits.AnnotationResolved;
			}
		} else if (node instanceof TypeDeclaration) {
			TypeDeclaration typeDeclaration = (TypeDeclaration) node;

//			if (typeDeclaration.binding instanceof LocalTypeBinding) {
//				typeDeclaration.binding = null;
//			} else
			if (typeDeclaration.binding != null) {
				SourceTypeBinding sourceTypeBinding = typeDeclaration.binding;
				
				sourceTypeBinding.tagBits &= ~TagBits.AnnotationResolved;
				
//					Constructor<UnresolvedReferenceBinding> unresolvedReferenceBindingConstructor =
//					ReflectUtils.getInaccessibleConstructor(
//							UnresolvedReferenceBinding.class, char[][].class, PackageBinding.class);
	//
//				//TODO The PackageBinding below is not correct; for now use the same 'packageName' from 'compilationUnitDeclaration'
//				typeDeclaration.binding.superclass = ReflectUtils.newInstance(unresolvedReferenceBindingConstructor,
//						new char[][] { "java".toCharArray(), "lang".toCharArray(), "Object".toCharArray() },
//						new PackageBinding(
//								new char[][] { "java".toCharArray(), "lang".toCharArray() }, null, lookupEnvironment));
//					for (int i = 0; i < sourceTypeBinding.superInterfaces.length; i++) {
//						ReferenceBinding referenceBinding = sourceTypeBinding.superInterfaces[i];
//
//						if (P)
//					}
//					for (ReferenceBinding referenceBinding : sourceTypeBinding.superInterfaces) {
//						if (Pa
//					}
//				}
				
			}
		} else if (node instanceof NameReference) {
//			((NameReference) node).actualReceiverType = null;
		}
			
		return true;
	}

	@Override
	public void endVisit(ASTNodeVisitorContext context, ASTNode node, Scope scope) {
		// Do nothing
	}

//	private static void updateSourceTypeBinding(ReferenceBinding referenceBinding) {
//		Field superInterfacesField = ReflectUtils.findPublicField(referenceBinding.getClass(), "superInterfaces");
//		if (superInterfacesField != null) {
//			ReferenceBinding[] superInterfaces =
//					(ReferenceBinding[]) ReflectUtils.fieldValue(superInterfacesField, referenceBinding);
//
//			if (superInterfaces != null && superInterfaces != Binding.NO_SUPERINTERFACES) {
//				for (int i = 0; i < superInterfaces.length; i++) {
//					ReferenceBinding superInterfaceBinding = superInterfaces[i];
//
//					
//				}
//			}
//			
//		}
//		
////		ReferenceBinding[] superInterfaces
//	}
	
}
